#pragma once

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>

#include "luster_int.hh"
#include "luster_lexpr.hh"
#include "luster_log.hh"
#include "luster_status.hh"

namespace luster {

struct Parser {
	Char const *text{};
	S32 curr{};
	UInt err_pos{};
};

Status parse_lexpr(Parser *p, Lexpr *lexpr);

#define luster_TOKEN_TAG_MAP(_) \
	_(INTEGER) /* 10, -12 */ \
	_(FLOAT) /* */ \
	_(STRING) /* "Hello" */ \
\
	_(DOT) /* . */ \
	_(SYMBOL) /* foo, bar */ \
\
	_(OPEN) /* ( */ \
	_(CLOSE) /* ) */ \
	_(OPEN_I) /* [ */ \
	_(CLOSE_I) /* ] */ \
	_(OPEN_D) /* { */ \
	_(CLOSE_D) /* } */ \
	_(COMMA) /* ; */ \
	_(COLON) /* : */ \
	_(SEMICOLON) /* ; */ \
	_(STRUCT)

enum TokenTag {
#define _(NAME) TOKEN_##NAME,
	luster_TOKEN_TAG_MAP(_)
#undef _
};

static inline Logger operator<<(Logger logger, TokenTag tag) {
	static char const *name[] = {
#define _(NAME) #NAME,
		luster_TOKEN_TAG_MAP(_)
#undef _
	};
	logger << name[(UInt)tag];
	return logger;
}

struct Token {
	TokenTag tag{};

	union {
		S64 s64;
		Slice string;
	} as{};
};

Status parse_token(Parser *p, Token *token);

} // namespace luster
